import Node_Classes.TreeNodeObj;

/**
 * Diese Klasse dient dazu, die Funktionselemente korrekt abzuspeichern. Dies geschieht durch eine BinärBaum-Struktur. 
 * Die Klasse besitzt daher ein root und ein currentNode Objekt, mit deren Hilfe die Baumstruktur erzeugt wird. 
 * Zusätzlich besitzt die Klasse einige Methoden, die helfen, 
 * die Funktionselemente an die richtigen Stellen abzuspeichern.
 * @author c.barsch
 */
public class Tree {

	/** isPot ist ein Boolean, der angibt, ob ein Tree ein Exponent sein soll
	 * (also nach einem ^ eingefuegt werden soll)
	*/ 
	private boolean isPot = false;
	private TreeNodeObj root;
	private TreeNodeObj currentNode;

	// default Konstruktor
	public Tree() {
	}

	/** liefert das Wurzelelement */
	protected TreeNodeObj getRoot() {
		return this.root;
	}

	/** setzt den Wert von isPot */
	protected void set_isPot(boolean wert) {
		this.isPot = wert;
	}
	/** liefert den Wert von isPot */
	protected boolean get_isPot() {
		return this.isPot;
	}

	
	 
	/**
	 * 	Diese Methode fuegt ein Element/Node (tn) in den Baum an die richtige Stelle 
	 * ein. Durch isPot wird geprueft, ob der currentNode verschoben werden muss 
	 * oder nicht!
	 * Das Element wird an currentNode angehangen
	 * (Beispiel: Bei 3^2*1 muss der CN nach dem einfuegen der 2 auf
	 * dem ^ Node und nicht dem Node mit der 2 stehen. Dies wird durch den
	 * Boolean isPot gewaehrleistet)
	 * @param tn Ist der entsprechende Node der eingefuegt werden soll
	 * @param isPot Prueft ob der Baum eine Potenz ist und setzt currentNode dementsprechend
	 * @return liefert true bei erfolgreichem einfuegen,  ansonsten false
	 */
	protected boolean addElement(TreeNodeObj tn, boolean isPot) {
		// wenn noch kein Element im Baum vorhanden ist, setze es als root
		if (this.root == null) {
			this.root = tn;
			this.currentNode = this.root;
			return true;
		}
		// wenn der linke Knoten frei ist, setze das Objekt als linken
		// Knoten
		if (currentNode != null && currentNode.left == null) {
			currentNode.left = tn;
			currentNode.left.father = currentNode;

			// Falls das einzufuegende eine Potenz ist, soll der currentNode
			// nicht veraendert werden
			if (!isPot) {
				currentNode = currentNode.left;
			}
			return true;
		}
		// wenn der rechte Knoten frei ist, setze das Element in den Rechten
		// Knoten
		if (currentNode != null && currentNode.right == null) {
			currentNode.right = tn;
			currentNode.right.father = currentNode;

			if (!isPot) {
				currentNode = currentNode.right;
			}
			return true;
		}
		return false;
	}

	/**
	 * Diese Methode fuegt ein Element/Node (tn) in den Baum ein. Das Element wird als Vater von currentNode
	 * eingesetzt
	 * @param tn ist das entsprechende Node-Objekt das als Vater eingefuegt werden soll
	 * @return liefert true zurueck
	 */
	protected boolean addAsFather(TreeNodeObj tn) {
		// wenn currentNode == root ist, dann wird der neue Knoten als Vater
		// hinzugefügt
		if (this.currentNode == this.root) {
			tn.left = this.root;
			this.root.father = tn;
			this.root = tn;
			this.currentNode = tn;
			return true;
		} else {
			// newNode uebernimmt die vater verknüpfung
			tn.father = currentNode.father;

			// die Verknuepfung vom Vater muss auf newNode umgeleitet werden
			if (currentNode.father.left == currentNode) {
				currentNode.father.left = tn;
			} else {
				currentNode.father.right = tn;
			}

			// newNode fuegt den currentNode als linken Sohn hinzu
			tn.left = currentNode;
			// der Vater von current Node wird newNode
			currentNode.father = tn;
			currentNode = currentNode.father;
			return true;
		}
	}

	/**
	 * das Node-Objekt tn wird als neue Wurzel hinzugefuegt
	 * @param tn ist das entsprechende Node-Objekt das als root eingefuegt werden soll
	 * @return
	 */
	protected boolean addAsRoot(TreeNodeObj tn) {
		tn.left = this.root;
		this.root.father = tn;
		this.root = tn;
		currentNode = tn;
		return true;
	}

	/**
	 * Diese Methode setzt den currentNode auf das Vater Element des currentNodes
	 * @return liefert true zurueck
	 */
	protected boolean CNasFather() {
		this.currentNode = this.currentNode.father;
		return true;
	}

}
